using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace BlackjackGUI
{
   public partial class MainForm : Form
   {
      public MainForm()
      {
         m_Player = new CPlayer();
         m_DealerCards = new LinkedList<CCard>();

         InitializeComponent();
         SetupTable();
      }

      private void SetupTable()
      {
         ClearTable();
         m_shoe = new CShoe(6);
         m_shoe.Shuffle();
         UpdateShoeDisplay();
         UpdatePlayerCash();
         m_count = 0;
      }

      private void ClearTable()
      {
         if (m_Player != null)
         {
            for(int i=0;i<m_Player.NumHands();i++)
            {
               RemoveHandFromTable(m_Player[i]);
            }
            m_Player.Clear();
         }
         if (m_DealerCards != null)
         {
            RemoveHandFromTable(m_DealerCards);
            m_DealerCards.Clear();
         }
         toolStripStatusLabelLeft.Text = "";
         toolStripStatusLabelRight.Text = "";
         lblDealerTotal.Text = "0";
         lblPlayerTotal.Text = "0";
         m_currentHand = 0;

      }

      private void Cleanup()
      {
         ClearTable();

         if (m_Player != null)
         {
            m_Player = null;
         }
         if (m_DealerCards != null)
         {
            m_DealerCards = null;
         }
         if (m_shoe != null)
         {
            m_shoe = null;
         }
      }

      private void btnHit_Click(object sender, EventArgs e)
      {
         // check basic strategy
         CBasicStrategy bs = new CBasicStrategy();
         if(CBasicStrategy.MoveEnum.Hit == bs.MakeMove(m_DealerCards.First.Value.GetValue(), m_Player[m_currentHand]))
         {
            toolStripStatusLabelRight.Text = "Correct Move!";
         }
         else
         {
            toolStripStatusLabelRight.Text = "Should have " + bs.MakeMove(m_DealerCards.First.Value.GetValue(), m_Player[m_currentHand]).ToString();
         }
         // end check BS

         DealPlayer(m_currentHand);
         lblPlayerTotal.Text = m_Player[m_currentHand].Total.ToString();
         // Check for bust
         if (Convert.ToInt32(lblPlayerTotal.Text) > 21)
         {
            // Play next hand
            m_currentHand++;
            // Check for no more hands to play
            if (m_currentHand == m_Player.NumHands())
            {
               DealerPlay();
            }
            // If split earlier, must deal another card
            else if (m_Player[m_currentHand].Count == 1)
            {
               DealPlayer(m_currentHand);
            }
         }
         UpdateMarker();
         UpdateShoeDisplay();
      }

      private void btnDeal_Click(object sender, EventArgs e)
      {
         ClearTable();
         m_currBet = Convert.ToInt32(txtBet.Text);
         if (m_Player.Bet(m_currBet))
         {
            m_Player[m_currentHand].Bet = m_currBet;
            for (int i = 0; i < 2; i++)
            {
               DealPlayer(0);
               DealDealer();
            }
            lblPlayerTotal.Text = m_Player[0].Total.ToString();

            btnDeal.Enabled = false;
            btnHit.Enabled = true;
            btnDouble.Enabled = true;
            btnSplit.Enabled = true;
            btnStand.Enabled = true;
            UpdatePlayerCash();

            // Check for dealer blackjack
            if (m_DealerCards.First.Value.GetValue() == ValueEnum.ACE)
            {
               // Offer insurance?
            }
            if ((m_DealerCards.First.Value.GetValue() == ValueEnum.ACE) ||
                (m_DealerCards.First.Value.GetValue() == ValueEnum.KING) ||
                (m_DealerCards.First.Value.GetValue() == ValueEnum.QUEEN) ||
                (m_DealerCards.First.Value.GetValue() == ValueEnum.JACK) ||
                (m_DealerCards.First.Value.GetValue() == ValueEnum.TEN))
            {
               // check for blackjack
               if (Total(m_DealerCards) == 21)
               {
                  m_currentHand++;
                  DealerPlay();
               }
            }
         }
         else
         {
            toolStripStatusLabelLeft.Text = "You don't have enough money fool!";
         }
         UpdateMarker();
         UpdateShoeDisplay();
      }

      private void RemoveHandFromTable(CHand hand)
      {
         for (int ii = 0; ii < hand.Count; ii++)
         {
            Controls.Remove(hand[ii].GetControl());
         }
      }

      private void RemoveHandFromTable(LinkedList<CCard> hand)
      {
         LinkedListNode<CCard> iter = hand.First;
         for (int ii = 0; ii < hand.Count; ii++)
         {
            Controls.Remove(iter.Value.GetControl());
            iter = iter.Next;
         }
      }

      private void DealPlayer(int hand)
      {
         CCard dealtCard = m_shoe.DealOneCard();
         dealtCard.SetImage(150, 215, 315 + 40 * m_Player[hand].Count, 400 - 20 * m_Player[hand].Count, false);

         // remove cards from GUI
         RemoveHandFromTable(m_Player[hand]);

         // add cards to GUI again for correct z-order
         m_Player[hand].AddCard(dealtCard);

         int count = m_Player[hand].Count;
         for (int ii = 0; ii < count; ii++)
         {
            Controls.Add(m_Player[hand][count - 1 - ii].GetControl());
            m_Player[hand][count - 1 - ii].GetControl().MainFormIndex = Controls.IndexOf(m_Player[hand][count - 1 - ii].GetControl());
         }
         try
         {
            m_Player.AlignCards();
         }
         catch (Exception e)
         {
            MessageBox.Show(e.Message);
         }
      }

      private void DealDealer()
      {
         CCard dealtCard = m_shoe.DealOneCard();
         if (m_DealerCards.Count == 0)
         {
            // first card
            dealtCard.SetImage(150, 215, 320, 60, false);
         }
         else if (m_DealerCards.Count == 1)
         {
            // second card
            dealtCard.SetImage(150, 215, 475, 60, true);
         }
         else
         {
            // all other cards
            dealtCard.SetImage(150, 215, 475 + 40 * (m_DealerCards.Count - 1), 60 - 20 * (m_DealerCards.Count - 1), false);
         }

         // remove cards from GUI
         RemoveHandFromTable(m_DealerCards);

         // add cards to GUI again for correct z-order
         m_DealerCards.AddLast(dealtCard);
         LinkedListNode<CCard>  iter = m_DealerCards.Last;
         for (int ii = 0; ii < m_DealerCards.Count; ii++)
         {
            Controls.Add(iter.Value.GetControl());
            iter.Value.GetControl().MainFormIndex = Controls.IndexOf(iter.Value.GetControl());
            iter = iter.Previous;
         }
      }

      private int Total(LinkedList<CCard> cards)
      {
         int retVal = 0;
         bool softHand = false;
         if (cards.Count > 0)
         {
            LinkedListNode<CCard> iter = cards.First;
            for (int ii = 0; ii < cards.Count; ii++)
            {
               ValueEnum currVal = iter.Value.GetValue();
               if (currVal == ValueEnum.ACE)
               {
                  if (retVal > 10)
                  {
                     retVal += 1;
                  }
                  else
                  {
                     retVal += 11;
                     softHand = true;
                  }
               }
               else if (currVal == ValueEnum.KING || currVal == ValueEnum.QUEEN || currVal == ValueEnum.JACK)
               {
                  retVal += 10;
               }
               else
               {
                  retVal += (int)currVal;
               }
               iter = iter.Next;
            }

            // If we busted with an Ace as 11, recount it as 1
            if (retVal > 21 && softHand)
            {
               retVal = 0;
               iter = cards.First;
               for (int ii = 0; ii < cards.Count; ii++)
               {
                  ValueEnum currVal = iter.Value.GetValue();
                  if (currVal == ValueEnum.ACE)
                  {
                     retVal += 1;
                  }
                  else if (currVal == ValueEnum.KING || currVal == ValueEnum.QUEEN || currVal == ValueEnum.JACK)
                  {
                     retVal += 10;
                  }
                  else
                  {
                     retVal += (int)currVal;
                  }
                  iter = iter.Next;
               }
            }
         }
         return retVal;
      }

      private bool SoftSeventeen(LinkedList<CCard> hand)
      {
         int value = 0;
         bool softHand = false;
         if (hand.Count > 0)
         {
            LinkedListNode<CCard> iter = hand.First;
            for (int ii = 0; ii < hand.Count; ii++)
            {
               ValueEnum currVal = iter.Value.GetValue();
               if (currVal == ValueEnum.ACE)
               {
                  if (softHand)
                  {
                     value += 1;
                  }
                  else
                  {
                     value += 11;
                     softHand = true;
                  }
               }
               else if (currVal == ValueEnum.KING || currVal == ValueEnum.QUEEN || currVal == ValueEnum.JACK)
               {
                  value += 10;
               }
               else
               {
                  value += (int)currVal;
               }
               iter = iter.Next;
            }
         }
         return (softHand && (value == 17));
      }

      private void btnSplit_Click(object sender, EventArgs e)
      {
         // check basic strategy
         CBasicStrategy bs = new CBasicStrategy();
         if (CBasicStrategy.MoveEnum.Split == bs.MakeMove(m_DealerCards.First.Value.GetValue(), m_Player[m_currentHand]))
         {
            toolStripStatusLabelRight.Text = "Correct Move!";
         }
         else
         {
            toolStripStatusLabelRight.Text = "Should have " + bs.MakeMove(m_DealerCards.First.Value.GetValue(), m_Player[m_currentHand]).ToString();
         }
         // end check BS

         if (m_Player.Splitable(m_currentHand))
         {
            if (m_Player.Bet(m_currBet))
            {
               toolStripStatusLabelLeft.Text = "";
               m_Player.Split(m_currentHand);
               DealPlayer(m_currentHand);
            }
            else
            {
               toolStripStatusLabelLeft.Text = "You do not have the funds to split.";
            }
         }
         else
         {
            toolStripStatusLabelLeft.Text = "You cannot split right now!";
         }
         UpdateMarker();
         UpdateShoeDisplay();
      }

      private void btnStand_Click(object sender, EventArgs e)
      {
         // check basic strategy
         CBasicStrategy bs = new CBasicStrategy();
         if (CBasicStrategy.MoveEnum.Stand == bs.MakeMove(m_DealerCards.First.Value.GetValue(), m_Player[m_currentHand]))
         {
            toolStripStatusLabelRight.Text = "Correct Move!";
         }
         else
         {
            toolStripStatusLabelRight.Text = "Should have " + bs.MakeMove(m_DealerCards.First.Value.GetValue(), m_Player[m_currentHand]).ToString();
         }
         // end check BS

         m_currentHand++;
         if (m_currentHand == m_Player.NumHands())
         {
            DealerPlay();
         }
         else
         {
            DealPlayer(m_currentHand);
            lblPlayerTotal.Text = m_Player[m_currentHand].Total.ToString();
         }
         UpdateMarker();
      }

      private void btnDouble_Click(object sender, EventArgs e)
      {
         // check basic strategy
         CBasicStrategy bs = new CBasicStrategy();
         if (CBasicStrategy.MoveEnum.Double == bs.MakeMove(m_DealerCards.First.Value.GetValue(), m_Player[m_currentHand]))
         {
            toolStripStatusLabelRight.Text = "Correct Move!";
         }
         else
         {
            toolStripStatusLabelRight.Text = "Should have " + bs.MakeMove(m_DealerCards.First.Value.GetValue(), m_Player[m_currentHand]).ToString();
         }
         // end check BS

         if (m_Player[m_currentHand].Count == 2)
         {
            if (m_Player.Bet(m_currBet))
            {
               m_Player[m_currentHand].Bet = 2 * m_currBet;
               DealPlayer(m_currentHand);
               lblPlayerTotal.Text = m_Player[m_currentHand].Total.ToString();
               m_currentHand++;
               if (m_currentHand == m_Player.NumHands())
               {
                  DealerPlay();
               }
               else
               {
                  DealPlayer(m_currentHand);
                  lblPlayerTotal.Text = m_Player[m_currentHand].Total.ToString();
               }
            }
            else
            {
               toolStripStatusLabelLeft.Text = "You do not have the funds to double.";
            }
         }
         else
         {
            toolStripStatusLabelLeft.Text = "Cannot Double Yet!";
         }
         UpdateMarker();
      }

      private void DealerPlay()
      {
         bool dealer_needs_to_play = false;
         bool dealer_busted = false;
         int dealer_total = 0;
         if (m_currentHand == m_Player.NumHands())
         {
            // update buttons
            btnHit.Enabled = false;
            btnDouble.Enabled = false;
            btnSplit.Enabled = false;
            btnStand.Enabled = false;
            // Flip dealer card
            m_DealerCards.First.Next.Value.FlipCard();

            toolStripStatusLabelLeft.Text = "";

            for (int ii = 0; ii < m_Player.NumHands(); ii++)
            {
               // Check for player hands that did not bust
               if (m_Player[ii].Blackjack)
               {
                  m_Player.AddMoney((3 * m_Player[ii].Bet) / 2 + m_Player[ii].Bet);
                  toolStripStatusLabelLeft.Text += "Blackjack! (" + (ii + 1) + ")  ";
               }
               else if (!m_Player[ii].Bust)
               {
                  dealer_needs_to_play = true;
               }
               else
               {
                  toolStripStatusLabelLeft.Text += "Bust (" + (ii + 1) + ")  ";
               }
            }

            // If the player did not bust, the dealer needs to continue playing
            if(dealer_needs_to_play)
            {
               while ((Total(m_DealerCards) < 17) || SoftSeventeen(m_DealerCards))
               {
                  DealDealer();
               }
               // update dealer hand
               dealer_total = Total(m_DealerCards);
               lblDealerTotal.Text = dealer_total.ToString();

               if (Total(m_DealerCards) > 21)
               {
                  dealer_busted = true;
               }
               
               // Pay out to the player as needed
               for (int ii = 0; ii < m_Player.NumHands(); ii++)
               {
                  // check if hand still in
                  if((! m_Player[ii].Bust) && ( ! m_Player[ii].Blackjack))
                  {
                     if( dealer_busted)
                     {
                        // you win
                        m_Player.AddMoney(2 * m_Player[ii].Bet);
                        toolStripStatusLabelLeft.Text = "Dealer busts, you win!";
                     }
                     else if(dealer_total > m_Player[ii].Total)
                     {
                        // you lose - Do nothing
                        toolStripStatusLabelLeft.Text = "You lose";
                     }
                     else if(dealer_total == m_Player[ii].Total)
                     {
                        // push
                        m_Player.AddMoney(m_Player[ii].Bet);
                        toolStripStatusLabelLeft.Text = "Push";
                     }
                     else
                     {
                        // you win
                        m_Player.AddMoney(2 * m_Player[ii].Bet);
                        toolStripStatusLabelLeft.Text = "You win!";
                     }
                  }
               }
            }

            // Update buttons
            btnDeal.Enabled = true;
            // Refresh Shoe remaining display
            UpdateShoeDisplay();
            // Shuffle deck if shoe is too low
            if (pbShoe.Value < 17)
            {
               SetupTable();
            }
            // Update player total to reflect wins and loses
            UpdatePlayerCash();
            // Update "The Count"
            UpdateCount();
         }
      }

      private void UpdateCount()
      {
         // TODO - count player's hands
         for (int i = 0; i < m_Player.NumHands(); i++)
         {
            for (int j = 0; j < m_Player[i].Count; j++)
            {
               if(m_Player[i][j].GetValue() >= ValueEnum.TEN || m_Player[i][j].GetValue() == ValueEnum.ACE)
               {
                  m_count--;
               }
               else if (m_Player[i][j].GetValue() < ValueEnum.SEVEN)
               {
                  m_count++;
               }
            }
         }

         // count dealer cards
         LinkedListNode<CCard> dealer_card = m_DealerCards.First;
         for (int i = 0; i < m_DealerCards.Count; i++)
         {
            if (dealer_card.Value.GetValue() >= ValueEnum.TEN || dealer_card.Value.GetValue() == ValueEnum.ACE)
            {
               m_count--;
            }
            else if (dealer_card.Value.GetValue() < ValueEnum.SEVEN)
            {
               m_count++;
            }
            if (i != (m_DealerCards.Count - 1))
            {
               dealer_card = dealer_card.Next;
            }
         }
         lblCount.Text = m_count.ToString();
      }

      private void UpdateShoeDisplay()
      {
         pbShoe.Value = m_shoe.ShoePercentRemaining();
      }

      private void UpdatePlayerCash()
      {
         txtTotalPlayerCash.Text = m_Player.AmtMoney().ToString();
      }

      private void UpdateMarker()
      {
         int numHands = m_Player.NumHands();
         if (numHands == 0)
         {
            m_Marker.Visible = false;
            return;
         }
         else
         {
            m_Marker.Visible = true;
            if (numHands == 1)
            {
               m_Marker.Location = new Point(350, 617);
            }
            else if (numHands == 2)
            {
               if (m_currentHand == 0)
               {
                  m_Marker.Location = new Point(250, 617);
               }
               else
               {
                  m_Marker.Location = new Point(550, 617);
               }
            }
            else if (numHands == 3)
            {
               if (m_currentHand == 0)
               {
                  m_Marker.Location = new Point(100, 617);
               }
               else if (m_currentHand == 1)
               {
                  m_Marker.Location = new Point(400, 617);
               }
               else
               {
                  m_Marker.Location = new Point(700, 617);
               }
            }
            else
            {
               throw new Exception("UpdateMarker does Not Handle this many hands! Please Contact Pete...");
            }

            // Update Debug Display
            if (m_currentHand < numHands)
            {
               lblHand.Text = m_Player[m_currentHand].Total.ToString();
            }
            else
            {
               lblHand.Text = m_Player[m_currentHand-1].Total.ToString();
            }
         }
      }

      private void debugModeToolStripMenuItem_Click(object sender, EventArgs e)
      {
         if ( debugModeToolStripMenuItem.Checked )
         {
            lblCount.Visible = true;
            lblCount_Debug.Visible = true;
            lblHand.Visible = true;
            lblHand_Debug.Visible = true;
         }
         else
         {
            lblCount.Visible = false;
            lblCount_Debug.Visible = false;
            lblHand.Visible = false;
            lblHand_Debug.Visible = false;
         }
      }

      private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
      {
         AboutBox about_me = new AboutBox();
         about_me.ShowDialog();
         about_me.Dispose();
      }

      private void simulationModeToolStripMenuItem_Click(object sender, EventArgs e)
      {
         MessageBox.Show("Sorry chap, not implemented yet...");
      }

      private CPlayer m_Player;
      private int m_currBet;
      private int m_currentHand;
      private LinkedList<CCard> m_DealerCards;
      private CShoe m_shoe;
      private int m_count;
   }
}